home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / misc / emu / Apex-src.lha / LOAD.XPL < prev    next >
Text File  |  2001-09-30  |  13KB  |  449 lines

  1. \LOAD.XPL    JUL-07-88
  2. \Loader for .OBJ files
  3. \Written by Loren Blaney for DFM Engineering
  4.  
  5. \REVISION HISTORY:
  6. \FEB-17-86, Original
  7. \MAY-01-86, Modified to load assembly files
  8. \OCT-12-86, Option to load anywhere, and modified for new system.
  9. \DEC-12-86, Major clean up, added multiple file capability.
  10. \FEB-02-87, Allow multiple file names to be in lowercase, and
  11. \ use START vector to determine if .68K code set up SYSPAG parameters.
  12. \APR-10-87, Change string conventions
  13. \JUL-07-88, Change default load location (from $3000 to $1000), set default
  14. \ heap and stack, change range conventions so that the maximum address now
  15. \ includes the end point.
  16. \
  17. \NOTES:
  18. \This program loads and (optionally) starts the .OBJ file which is
  19. \ produced by either the compiler or the assembler. This loader combines
  20. \ the capabilities of the following programs which run on the Apple:
  21. \ LOAD, the loader in I2L, LODBX, LODIX, SXLOD, and SYSLOD.
  22. \
  23. \Loading this loader is a two-step process: Use the existing loader to
  24. \ load the new loader at $1000, and make a .SAV file of this temporary
  25. \ loader (LOADX). Now use the temporary loader to load the new loader at
  26. \ $76800. This temporary loader is also used to load APEX.OBJ.
  27.  
  28. code
  29. ABS=0,        RAN=1,        REM=2,        RESERVE=3,
  30. SWAP=4,        EXTEND=5,    RESTART=6,    CHIN=7,
  31. CHOUT=8,    CRLF=9,        INTIN=10,    INTOUT=11,
  32. TEXT=12,    OPENI=13,    OPENO=14,    CLOSE=15,
  33. ABORT=16,    SCAN=24,    HEXIN=26,    HEXOUT=27,
  34. OPENF=29;
  35.  
  36. ext    CHIN3=$C00;
  37.  
  38. int    CHAR,        \Character read from disk
  39.     CHARKB,        \Character read from keyboard
  40.     MINADDR,    \Minimum address at execution time
  41.     MAXADDR,    \Maximum address +1 at execution time
  42.     OFFSET,        \Offset to add to go from execution to load address
  43.     DEFAULT,    \Array of default settings
  44.     VSTARTX,    \SYSPAG JMP vector to start of loaded program
  45.     LINKPTR,    \Pointer to 'LINK' jump table
  46.     LINEPTR;    \Pointer (index) into LINEBUF
  47. addr    BASEADDR,    \Execution base address of current module (also @)
  48.     LOADADDR,    \Load base address (@ + OFFSET)
  49.     FIRSTBASE,    \Execution base address of first module
  50.     FIRSTLOAD,    \Load base address of first module
  51.     LINEBUF;    \Line buffer: holds copy of keyboard buffer
  52.  
  53. reg int    PC;        \The current load address (relative to BASEADDR)
  54.  
  55. def    TV=0, KB=0;
  56. def    BEL=$07, CR=$0D, EOF=$1A, SP=$20;
  57. def    INTSIZE=4;    \Number of bytes in an integer
  58.  
  59. \----------------------------------------------------------------------\
  60.  
  61. func    GETCH;        \Get next character from LINEBUF
  62. int    CH;
  63. begin
  64. CH:= LINEBUF(LINEPTR);
  65. if CH >= ^a & CH <= ^z then CH:= CH & $DF;    \Convert to upper case
  66. LINEPTR:= LINEPTR +1;
  67. return CH;
  68. end;    \GETCH
  69.  
  70.  
  71.  
  72. proc    ERROR(STR);    \Display error message and abort
  73. addr    STR;
  74. begin
  75. TEXT(TV,"
  76. OH OH - ");
  77. CHOUT(TV,BEL);
  78. TEXT(TV,STR);
  79. CRLF(TV);
  80. ABORT;
  81. end;    \ERROR
  82.  
  83. \----------------------------------------------------------------------\
  84.  
  85. func    HEXBYTE;    \Read in 2 chars and return the value of the hex byte
  86. reg int    CH, HEX;    \ (Optimized for speed)
  87. begin
  88. loop    begin
  89.     CH:= CHAR;
  90.     if CH <= ^9 then
  91.         if CH >= ^0 then [HEX:= (CH -^0) <<4; quit];
  92.     if CH >= ^A then
  93.         if CH <= ^F then [HEX:= (CH -$37) <<4; quit];
  94.     ERROR("HEX CHARACTER EXPECTED");    \(never returns)
  95.     end;
  96.  
  97. CH:= CHIN3;
  98. CHAR:= CHIN3;
  99. if CH <= ^9 then
  100.     if CH >= ^0 then return HEX + CH -^0;
  101. if CH >= ^A then
  102.     if CH <= ^F then return HEX + CH -$37;
  103. ERROR("HEX CHARACTER EXPECTED");
  104. end;    \HEXBYTE
  105.  
  106.  
  107.  
  108. func    HEXWORD;    \Read in 4 chars and return the value of the hex word
  109. return SWAP(HEXBYTE) + HEXBYTE;
  110.  
  111.  
  112.  
  113. func    HEXLONG;  \Read in 8 chars and return the value of the hex long word
  114. return HEXWORD <<16 + HEXWORD;
  115.  
  116. \----------------------------------------------------------------------
  117.  
  118. proc    STOBYTE(BYTE);    \Store a byte at the current load address
  119. int    BYTE;
  120. reg int    I;
  121. begin
  122. \Strip out any bytes that are outside the load range:
  123. I:= PC + BASEADDR;
  124. if I >= MAXADDR then [CHOUT(TV,^+); return];
  125. if I < MINADDR then [CHOUT(TV,^-); return];
  126.  
  127. LOADADDR(PC):= BYTE;
  128. PC:= PC +1;
  129. end;    \STOBYTE
  130.  
  131. \----------------------------------------------------------------------
  132.  
  133. proc    GETPC;        \(;) Read in a relative load address
  134. \A 4-digit base-relative address follows the ";". The base-relative PC is
  135. \ set to this value.
  136. begin
  137. PC:= HEXWORD;
  138. end;    \GETPC
  139.  
  140.  
  141.  
  142. proc    GETFIXED;    \(^) Fix a forward reference
  143. \A 4-digit base-relative address follows the "^". The contents at this address
  144. \ must be changed to point to the current PC value (using relative addressing).
  145. int    ADDR,        \Base-relative address whos contents need "fixing"
  146.     RELADDR;    \Relative address value pointing forward to current PC
  147. begin
  148. ADDR:= HEXWORD;
  149. RELADDR:= PC -ADDR;
  150.  
  151. LOADADDR(ADDR):= SWAP(RELADDR);
  152. LOADADDR(ADDR+1):= RELADDR;
  153. end;    \GETFIXED
  154.  
  155.  
  156.  
  157. proc    GETABS;        \(*) Relocate an absolute address
  158. \An 8-digit, base-relative address follows the "*". The value of this address
  159. \ must be changed to its equivalent absolute execution address.  This is only
  160. \ used for multi-dimensional, constant arrays.
  161. int    ADDR;        \Base-relative address to be converted to absolute addr
  162. addr    A;
  163. begin
  164. ADDR:= HEXLONG;                \Get the 8-digit, base-relative addr
  165. ADDR:= ADDR + BASEADDR;            \Convert to absolute execution address
  166. A:= addr ADDR;                \Access the individual bytes of ADDR
  167. STOBYTE(A(0));                \Load them, MSB first
  168. STOBYTE(A(1));
  169. STOBYTE(A(2));
  170. STOBYTE(A(3));
  171. end;    \GETABS
  172.  
  173.  
  174.  
  175. proc    GETBASE;    \(@) Read in a base address
  176. \An 8-digit absolute address follows the "@". The base address is
  177. \ set to this value.
  178. begin
  179. BASEADDR:= HEXLONG;
  180. LOADADDR:= BASEADDR + OFFSET;        \Convert to load address
  181. PC:= 0;
  182. end;    \GETBASE
  183.  
  184.  
  185.  
  186. proc    GETABS2;    \(#) Relocate an absolute address
  187. \An 8-digit, base-relative address follows the "#". The value of this address
  188. \ must be changed to its equivalent absolute execution address.  This is only
  189. \ used for jumping to linked procedures in external modules.
  190. int    ADDR;        \Base-relative address to be converted to absolute addr
  191. addr    A;
  192. begin
  193. ADDR:= HEXLONG;                \Get the 8-digit, base-relative addr
  194. ADDR:= ADDR + FIRSTBASE;        \Convert to absolute execution address
  195. A:= addr ADDR;                \Access the individual bytes of ADDR
  196. STOBYTE(A(0));                \Load them, MSB first
  197. STOBYTE(A(1));
  198. STOBYTE(A(2));
  199. STOBYTE(A(3));
  200. end;    \GETABS2
  201.  
  202.  
  203.  
  204. proc    GETLINKED;    \(%) Link an external procedure
  205. \The next entry in the external procedure jump table is set to point to the
  206. \ current absolute address. There must be a one-to-one correspondance between
  207. \ external procedure declarations (#) and linked procedures (%) otherwise
  208. \ the load image will be corrupted without warning.
  209. begin
  210. LINKPTR(0):= PC + BASEADDR - OFFSET;    \Store absolute address at link pointer
  211. LINKPTR:= LINKPTR +6;            \Point to next entry in jump table
  212. end;    \GETLINKED
  213.  
  214. \----------------------------------------------------------------------
  215.  
  216. proc    GETKBBUF;    \Get the keyboard buffer into LINEBUF
  217. \Since we may be loading more than one file and the keyboard buffer is
  218. \ used for obtaining defaults, we must save the keyboard buffer in LINEBUF.
  219. \Apex has read and set up the first file name, and it read the file name's
  220. \ terminator. We must back up to see if the terminator was a CR.
  221. int    CH,
  222.     LINPTRF,    \Keyboard buffer pointers on SYSPAG
  223.     LINPTRE;
  224. begin
  225. LINPTRF:= $690;
  226. LINPTRE:= $694;
  227.  
  228. LINEPTR:= 0;
  229. if LINPTRF(0) = LINPTRE(0) then        \The KB buffer is empty, stuff CR
  230.     LINEBUF(LINEPTR):= CR
  231. else    begin                \Read the KB buffer into LINEBUF
  232.     loop    begin
  233.         CH:= CHIN(KB);
  234.         LINEBUF(LINEPTR):= CH;
  235.         if CH = CR then quit;
  236.         if LINEPTR > 255 then ERROR("TOO MANY FILE NAMES");
  237.         LINEPTR:= LINEPTR +1;
  238.         end;
  239.     end;
  240. LINEPTR:= 0;
  241. end;    \GETKBBUF
  242.  
  243.  
  244.  
  245. proc    DOINCL;        \Include another .OBJ file
  246. int    BLK;        \Array: for SCAN
  247. addr    NAME,        \Array: holds file name
  248.     IDENT;        \Array: holds identifier name (file name or ext)
  249. int    INUNIT;        \Input unit number
  250.  
  251.  
  252.  
  253.     proc    GETIDENT;    \Get an identifier name and return it in IDENT
  254.     int    LEN;
  255.     begin
  256.     IDENT(0):= CHARKB;
  257.     CHARKB:= GETCH;
  258.     LEN:= 1;
  259.     loop case of
  260.       CHARKB>=^A & CHARKB<=^Z,  CHARKB>=^0 & CHARKB<=^9,  CHARKB=^_ :
  261.         begin
  262.         if LEN < 8 then
  263.             begin
  264.             IDENT(LEN):= CHARKB;
  265.             LEN:= LEN +1;
  266.             end;
  267.         CHARKB:= GETCH;
  268.         end
  269.     other quit;
  270.     for LEN:= LEN,7 do IDENT(LEN):= SP;
  271.     end;    \GETIDENT
  272.  
  273.  
  274.  
  275.     proc    GETNAME;    \Get name & unit of include file
  276.     int    I;
  277.     addr    INUNT;
  278.     begin
  279.     INUNT:= $56C;
  280.     INUNIT:= INUNT(0);        \Get the default input unit number
  281.     NAME(8):= ^O; NAME(9):= ^B; NAME(10):= ^J;    \Default extension
  282.  
  283.     if CHARKB>=^0 & CHARKB<=^9 then
  284.         begin            \We have an explicit unit number
  285.         INUNIT:= CHARKB & $0F;
  286.         CHARKB:= GETCH;        \Skip unit number
  287.         if CHARKB#^: then ERROR("^":^" EXPECTED");
  288.         CHARKB:= GETCH;        \Skip the colon
  289.         end;
  290.  
  291.     GETIDENT;
  292.     for I:=0,7 do NAME(I):= IDENT(I);
  293.  
  294.     if CHARKB=^. then
  295.         begin            \We have an explicit extension
  296.         CHARKB:= GETCH;        \Skip the "."
  297.         GETIDENT;
  298.         for I:=0,2 do NAME(I+8):= IDENT(I);
  299.         end;
  300.     end;    \GETNAME
  301.  
  302.  
  303.  
  304.     proc    STROUT(STR, SIZE);    \Output string to TV
  305.     addr    STR;
  306.     int    SIZE;
  307.     int    I;
  308.     begin
  309.     for I:= 0, SIZE-1 do
  310.         CHOUT(TV, STR(I));
  311.     end;    \STROUT
  312.  
  313.  
  314.  
  315. begin    \DOINCL
  316. NAME:= RESERVE(11);
  317. IDENT:= RESERVE(8);
  318. BLK:= RESERVE(2 *INTSIZE);
  319.  
  320. GETNAME;                \Get the file's name
  321. SCAN(INUNIT, BLK, NAME);        \Get its first and last blocks
  322. OPENF(INUNIT, BLK);
  323.  
  324. \Show the name of the inculded file:
  325. TEXT(TV,"
  326. INCLUDING: ");
  327. INTOUT(TV,INUNIT); CHOUT(TV,^:);
  328. STROUT(NAME,8); CHOUT(TV,^.); STROUT(NAME+8,3);
  329. end;    \DOINCL
  330.  
  331. \----------------------------------------------------------------------
  332.  
  333. proc    STARTUP;
  334. \Set up system page parameters and optionally start the program.
  335. \This procedure never returns.
  336. int    USRMEM,        \Base address of user program (variable in SYSPAG)
  337.     VRSTRTX,    \Entry point for a restart (variable in SYSPAG)
  338.     PROSIZ,        \User program size (VARIABLE IN SYSPAG)
  339.     HEAP,        \Base address of loaded program's heap space
  340.     STACK;        \Start of stack space (grows downward)
  341. ext    VSTART=$400;    \Start vector
  342. begin
  343. if VSTARTX(0) = -1 then            \Assume XPL code was loaded and
  344.     begin                \ set up the SYSPAG variables
  345.     VRSTRTX:= $408;
  346.     USRMEM:= $432;
  347.     PROSIZ:= $436;
  348.     HEAP:= $46E;
  349.     STACK:= $472;
  350.  
  351.     VSTARTX(0):= FIRSTLOAD;
  352.     VRSTRTX(0):= FIRSTLOAD;
  353.     USRMEM(0):= FIRSTLOAD;
  354.     \Program size in blocks: (one byte too big but beware of PC = 0)
  355.     PROSIZ(0):= (PC +BASEADDR -FIRSTBASE) /256 +1;
  356.     HEAP(0):= (BASEADDR +PC +1 ) &$FFFFFFFE;    \(use word boundary)
  357.     STACK(0):= MAXADDR & $FFFFFFFE;
  358.     end;
  359.  
  360. TEXT(TV,"
  361. PRESS ^"RETURN^" TO EXECUTE (OR CTRL-P TO SAVE) ");
  362. OPENI(KB);
  363. if CHIN(KB) then;            \Wait for RETURN key
  364.  
  365. \If LOADADDR # BASEADDR (i.e. if OFFSET # 0) then he shouldn't be doing this.
  366. \The user's XPL program will use the loader's SYSPAG parameters, heap space,
  367. \ and there will be no disk I/O (device #3).
  368. VSTART;
  369. exit;
  370. end;    \STARTUP
  371.  
  372. \----------------------------------------------------------------------
  373.  
  374. begin    \MAIN
  375. LINEBUF:= RESERVE(256);
  376.  
  377. TEXT(TV,"-- .OBJ LOADER, V1.0x12 --
  378.  
  379. ");
  380. GETKBBUF;
  381. CHARKB:= GETCH;
  382.  
  383. DEFAULT:= [$1000, $0000, $1FFFF, $0000];    \BASE, MIN, MAX, LOAD
  384.  
  385. loop    begin
  386.     TEXT(TV,"CHANGE DEFAULTS (N/Y)? ");
  387.     if (CHIN(KB) ! $20) # ^y then quit;
  388.     TEXT(TV,"XPL EXECUTION BASE ADDRESS?        $");
  389.     DEFAULT(0):= HEXIN(KB);
  390.     TEXT(TV,"MINIMUM EXECUTION ADDRESS?        $");
  391.     DEFAULT(1):= HEXIN(KB);
  392.     TEXT(TV,"MAXIMUM EXECUTION ADDRESS?        $");
  393.     DEFAULT(2):= HEXIN(KB);
  394.     TEXT(TV,"LOAD LOCATION OF MINIMUM ADDRESS?    $");
  395.     DEFAULT(3):= HEXIN(KB);
  396.     end;
  397.  
  398. BASEADDR:= DEFAULT(0);
  399. MINADDR:= DEFAULT(1);
  400. MAXADDR:= DEFAULT(2) +1;
  401. OFFSET:= DEFAULT(3) - MINADDR;
  402.  
  403. LOADADDR:= BASEADDR + OFFSET;
  404. FIRSTBASE:= BASEADDR;
  405. FIRSTLOAD:= LOADADDR;
  406.  
  407. LINKPTR:= LOADADDR +6;        \Point to first entry in 'LINK' jump table
  408.  
  409. \Set VSTARTX to an illegal address. This location must be altered. Either
  410. \ a loaded .68K program will do it, or STARTUP will.  If STARTUP does it,
  411. \ it will also set up some other SYSPAG parameters.
  412. VSTARTX:= $402;
  413. VSTARTX(0):= -1;            \(Will cause an address error)
  414.  
  415. OPENI(3);
  416. TEXT(TV,"LOADING...");
  417. loop    begin
  418.     PC:= 0;
  419.     CHAR:= CHIN3;            \One character look ahead
  420.     loop    begin
  421.         case CHAR of
  422.           ^;:    [CHAR:= CHIN3; GETPC];
  423.           ^^:    [CHAR:= CHIN3; GETFIXED];
  424.           ^*:    [CHAR:= CHIN3; GETABS];
  425.           ^@:    [CHAR:= CHIN3; GETBASE];
  426.           ^#:    [CHAR:= CHIN3; GETABS2];
  427.           ^%:    [CHAR:= CHIN3; GETLINKED];
  428.           EOF:    quit
  429.         other STOBYTE(HEXBYTE);
  430.         end;
  431.  
  432.     while CHARKB=^, ! CHARKB=SP do CHARKB:= GETCH;
  433.     if CHARKB = CR then quit;    \KB buffer is empty
  434.     DOINCL;                \Include next file
  435.  
  436.     BASEADDR:= BASEADDR +PC;
  437.     LOADADDR:= BASEADDR + OFFSET;
  438.     end;
  439.  
  440. STARTUP;
  441. end;    \MAIN
  442. y
  443.     DOINCL;                \Include next file
  444.  
  445.     BASEADDR:= BASEADDR +PC;
  446.     LOADADDR:= BASEADDR + OFFSET;
  447.     end;
  448.  
  449. STARTUP;